<?php
/**
 * Created by PhpStorm.
 * User: Chongquan
 * Time: 2018-01-10 20:04
 */

namespace app\workerman\controller;

use GatewayWorker\BusinessWorker;
use GatewayWorker\Gateway;
use GatewayWorker\Register;
use Workerman\Lib\Timer;
use Workerman\Worker;

/**
 * 名称 WebSocketController
 * 功能
 * @package app\workman\controller
 */
class SocketController
{

    const WS_PORT                  = 9101;
    const REGISTER_PORT            = 9201;
    const GATEWAY_INNER_PORT_BEGIN = 9301;

    const CPU_COUNT = 4; //cpu核数

    protected $monitor_dir   = null;// 监控的目录
    protected $monitor_files = [];//所有被监控的文件，key为inotify id

    private $_gatewayReady = false;//标记gateway是否启动

    /**
     * SocketController constructor.
     */
    public function __construct()
    {

        // 启动 WebSocket 服务 //启动 定时器 服务
        $this->registerAndBussiness()
             ->websocketServer();

        // 连接redis
        $this->connections();

        // 监控文件更新并自动
        $this->fileMonitor();

        Worker::runAll();
    }

    /**
     * registerAndBussiness
     * @author 王崇全
     * @date
     * @return $this
     */
    protected function registerAndBussiness()
    {
        //【1.1】register 服务必须是text协议
        $register       = new Register('text://127.0.0.1:'.self::REGISTER_PORT);
        $register->name = "gateway_register";

        //【1.2】 bussinessWorker 进程
        $worker                  = new BusinessWorker();
        $worker->name            = 'gateway_worker'; // worker名称
        $worker->count           = self::CPU_COUNT; // bussinessWorker进程数量
        $worker->eventHandler    = "app\workerman\controller\EventsController"; //事件处理类，默认是 Event 类
        $worker->registerAddress = '127.0.0.1:'.self::REGISTER_PORT; // 服务注册地址

        $this->_gatewayReady = true;

        return $this;
    }

    /**
     * websocketServer
     * @author 王崇全
     * @date
     * @return $this|bool
     */
    protected function websocketServer()
    {

        if (!$this->_gatewayReady) {
            echo "gateway not ready";

            return false;
        }

        // websocket_server 进程
        $gateway            = new Gateway("websocket://0.0.0.0:".self::WS_PORT);
        $gateway->name      = 'websocket_server'; // gateway名称，status方便查看
        $gateway->count     = self::CPU_COUNT; // gateway进程数
        $gateway->lanIp     = "127.0.0.1"; // 本机ip，分布式部署时使用内网ip

        // 内部通讯起始端口，假如$gateway->count=4，起始端口为 4000
        // 则一般会使用4000 4001 4002 4003 4个端口作为内部通讯端口
        $gateway->startPort = self::GATEWAY_INNER_PORT_BEGIN;

        $gateway->registerAddress = '127.0.0.1:'.self::REGISTER_PORT; // 服务注册地址

        $gateway->pingInterval         = 20; // 心跳间隔
        $gateway->pingNotResponseLimit = 0;
        $gateway->pingData             = ''; // 心跳数据

        // 当客户端连接上来时，设置连接的onWebSocketConnect，即在websocket握手时的回调
        $gateway->onConnect = function ($connection)
        {
            $connection->onWebSocketConnect = function ($connection, $http_header)
            {
                // 可以在这里判断连接来源是否合法，不合法就关掉连接
                // $_SERVER['HTTP_ORIGIN']标识来自哪个站点的页面发起的websocket链接
                //				if (false && $_SERVER['HTTP_ORIGIN'] != "192.168.1.3:8013")
                //				{
                //					$connection->close();
                //					var_dump("refused:".$_SERVER['HTTP_ORIGIN']);
                //				}
                // onWebSocketConnect 里面$_GET $_SERVER是可用的
                // var_dump($_GET, $_SERVER);
            };
        };

        $gateway->onWorkerStart = function ($gateway)
        {

            // 只在id编号为0的进程上设置定时器，其它1、2、3号进程不设置定时器
            // if ($gateway->id === 0) {}
        };

        return $this;
    }

    /**
     * 监控文件更新并自动 reload workerman
     * 安装inotify扩展
     * @author 王崇全
     * @date
     * @return void
     */
    protected function fileMonitor()
    {
        // 监控的目录，
        $this->monitor_dir = realpath(__DIR__.'/..');

        // worker
        $worker             = new Worker();
        $worker->name       = 'FileMonitor';
        $worker->reloadable = false;
        $last_mtime         = time();

        $worker->onWorkerStart = function ()
        {
            global $monitor_dir;
            // watch files only in daemon mode
            if (!Worker::$daemonize) {
                // chek mtime of files per second
                Timer::add(1, function ($monitor_dir)
                {

                    if (!$monitor_dir) {
                        return;
                    }
                    global $last_mtime;
                    // recursive traversal directory
                    $dir_iterator = new \RecursiveDirectoryIterator($monitor_dir);
                    $iterator     = new \RecursiveIteratorIterator($dir_iterator);
                    foreach ($iterator as $file) {
                        // only check php files
                        if (pathinfo($file, PATHINFO_EXTENSION) != 'php') {
                            continue;
                        }
                        // check mtime
                        if ($last_mtime < $file->getMTime()) {
                            echo $file." update and reload\n";
                            // send SIGUSR1 signal to master process for reload
                            posix_kill(posix_getppid(), SIGUSR1);
                            $last_mtime = $file->getMTime();
                            break;
                        }
                    }
                }, [$monitor_dir]);
            }
        };

    }

    /**
     * 初始化mysql和rdis链接
     * @author 王崇全
     * @date
     * @return void
     */
    protected function connections()
    {
        // 初始化 redis 连接
        if (config("cache.type") != "redis") {
            die("无法获取redis配置");
        }
        global $rd;
        $rd = new \Redis();
        $rd->pconnect(config("cache.host"), config("cache.port"));
        $rd->auth(config("cache.password")); //密码验证
    }

}